<!DOCTYPE html>
<html lang=zh>
<head>
  <meta charset="utf-8">
  
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
  <meta name="renderer" content="webkit">
  <meta http-equiv="Cache-Control" content="no-transform" />
  <meta http-equiv="Cache-Control" content="no-siteapp" />
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="format-detection" content="telephone=no,email=no,adress=no">
  <!-- Color theme for statusbar -->
  <meta name="theme-color" content="#000000" />
  <!-- 强制页面在当前窗口以独立页面显示,防止别人在框架里调用页面 -->
  <meta http-equiv="window-target" content="_top" />
  
  
  <title>设计模式—行为型模式 | Skyung-Blog</title>
  <meta name="description" content="设计模式—行为型模式">
<meta property="og:type" content="article">
<meta property="og:title" content="设计模式—行为型模式">
<meta property="og:url" content="https://skyung.gitee.io/Skyung/2022/03/01/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E2%80%94%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/index.html">
<meta property="og:site_name" content="Skyung-Blog">
<meta property="og:description" content="设计模式—行为型模式">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gitee.com/lifuh/picgo/raw/master/img/image-20220301172207826.png">
<meta property="og:image" content="https://gitee.com/lifuh/picgo/raw/master/img/webp.png">
<meta property="article:published_time" content="2022-02-28T16:00:00.000Z">
<meta property="article:modified_time" content="2022-02-28T16:00:00.000Z">
<meta property="article:author" content="Skyung">
<meta property="article:tag" content="java">
<meta property="article:tag" content="设计模式">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/lifuh/picgo/raw/master/img/image-20220301172207826.png">
  <!-- Canonical links -->
  <link rel="canonical" href="https://skyung.gitee.io/Skyung/2022/03/01/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E2%80%94%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/index.html">
  
    <link rel="alternate" href="/atom.xml" title="Skyung-Blog" type="application/atom+xml">
  
  
    <link rel="icon" href="images/favicon.png" type="image/x-icon">
  
  
<link rel="stylesheet" href="/Skyung/css/style.css">

  
  
  
  
<meta name="generator" content="Hexo 5.4.1"></head>


<body class="main-center" itemscope itemtype="http://schema.org/WebPage">
  <header class="header" itemscope itemtype="http://schema.org/WPHeader">
  <div class="slimContent">
    <div class="navbar-header">
      
      
      <div class="profile-block text-center">
        <a id="avatar" href="https://github.com/cofess" target="_blank">
          <img class="img-circle img-rotate" src="/Skyung/images/avatar.jpg" width="200" height="200">
        </a>
        <h2 id="name" class="hidden-xs hidden-sm">Skyung</h2>
        <h3 id="title" class="hidden-xs hidden-sm hidden-md">Web Developer</h3>
        <small id="location" class="text-muted hidden-xs hidden-sm"><i class="icon icon-map-marker"></i> Wuhan, China</small>
      </div>
      
      <div class="search" id="search-form-wrap">

    <form class="search-form sidebar-form">
        <div class="input-group">
            <input type="text" class="search-form-input form-control" placeholder="搜索" />
            <span class="input-group-btn">
                <button type="submit" class="search-form-submit btn btn-flat" onclick="return false;"><i class="icon icon-search"></i></button>
            </span>
        </div>
    </form>
    <div class="ins-search">
  <div class="ins-search-mask"></div>
  <div class="ins-search-container">
    <div class="ins-input-wrapper">
      <input type="text" class="ins-search-input" placeholder="想要查找什么..." x-webkit-speech />
      <button type="button" class="close ins-close ins-selectable" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
    </div>
    <div class="ins-section-wrapper">
      <div class="ins-section-container"></div>
    </div>
  </div>
</div>


</div>
      <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#main-navbar" aria-controls="main-navbar" aria-expanded="false">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
    </div>
    <nav id="main-navbar" class="collapse navbar-collapse" itemscope itemtype="http://schema.org/SiteNavigationElement" role="navigation">
      <ul class="nav navbar-nav main-nav ">
        
        
        <li class="menu-item menu-item-home">
          <a href="/Skyung/.">
            
            <i class="icon icon-home-fill"></i>
            
            <span class="menu-title">首页</span>
          </a>
        </li>
        
        
        <li class="menu-item menu-item-archives">
          <a href="/Skyung/archives">
            
            <i class="icon icon-archives-fill"></i>
            
            <span class="menu-title">归档</span>
          </a>
        </li>
        
        
        <li class="menu-item menu-item-categories">
          <a href="/Skyung/categories">
            
            <i class="icon icon-folder"></i>
            
            <span class="menu-title">分类</span>
          </a>
        </li>
        
        
        <li class="menu-item menu-item-tags">
          <a href="/Skyung/tags">
            
            <i class="icon icon-tags"></i>
            
            <span class="menu-title">标签</span>
          </a>
        </li>
        
        
        <li class="menu-item menu-item-repository">
          <a href="/Skyung/repository">
            
            <i class="icon icon-project"></i>
            
            <span class="menu-title">项目</span>
          </a>
        </li>
        
        
        <li class="menu-item menu-item-books">
          <a href="/Skyung/books">
            
            <i class="icon icon-book-fill"></i>
            
            <span class="menu-title">书单</span>
          </a>
        </li>
        
        
        <li class="menu-item menu-item-links">
          <a href="/Skyung/links">
            
            <i class="icon icon-friendship"></i>
            
            <span class="menu-title">友链</span>
          </a>
        </li>
        
        
        <li class="menu-item menu-item-about">
          <a href="/Skyung/about">
            
            <i class="icon icon-cup-fill"></i>
            
            <span class="menu-title">关于</span>
          </a>
        </li>
        
      </ul>
      
	
    <ul class="social-links">
    	
        <li><a href="/Skyung/null" target="_blank" title="Github" data-toggle=tooltip data-placement=top><i class="icon icon-github"></i></a></li>
        
        <li><a href="/Skyung/null" target="_blank" title="Weibo" data-toggle=tooltip data-placement=top><i class="icon icon-weibo"></i></a></li>
        
        <li><a href="/Skyung/null" target="_blank" title="Twitter" data-toggle=tooltip data-placement=top><i class="icon icon-twitter"></i></a></li>
        
        <li><a href="/Skyung/null" target="_blank" title="Behance" data-toggle=tooltip data-placement=top><i class="icon icon-behance"></i></a></li>
        
        <li><a href="/Skyung/atom.xml" target="_blank" title="Rss" data-toggle=tooltip data-placement=top><i class="icon icon-rss"></i></a></li>
        
    </ul>

    </nav>
  </div>
</header>

  
    <aside class="sidebar" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    
      <div class="widget">
    <h3 class="widget-title">公告</h3>
    <div class="widget-body">
        <div id="board">
            <div class="content">
                <p>欢迎交流与分享经验!</p>
            </div>
        </div>
    </div>
</div>

    
      
  <div class="widget">
    <h3 class="widget-title">分类</h3>
    <div class="widget-body">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/Skyung/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">学习笔记</a><span class="category-list-count">20</span></li></ul>
    </div>
  </div>


    
      
  <div class="widget">
    <h3 class="widget-title">标签</h3>
    <div class="widget-body">
      <ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/Skyung/tags/java/" rel="tag">java</a><span class="tag-list-count">19</span></li><li class="tag-list-item"><a class="tag-list-link" href="/Skyung/tags/jvm/" rel="tag">jvm</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/Skyung/tags/linux/" rel="tag">linux</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/Skyung/tags/redis/" rel="tag">redis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/Skyung/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/" rel="tag">多线程</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/Skyung/tags/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/" rel="tag">并发编程</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/Skyung/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" rel="tag">设计模式</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/Skyung/tags/%E9%9B%B6%E6%95%A3%E7%82%B9/" rel="tag">零散点</a><span class="tag-list-count">1</span></li></ul>
    </div>
  </div>


    
      
  <div class="widget">
    <h3 class="widget-title">标签云</h3>
    <div class="widget-body tagcloud">
      <a href="/Skyung/tags/java/" style="font-size: 14px;">java</a> <a href="/Skyung/tags/jvm/" style="font-size: 13px;">jvm</a> <a href="/Skyung/tags/linux/" style="font-size: 13px;">linux</a> <a href="/Skyung/tags/redis/" style="font-size: 13px;">redis</a> <a href="/Skyung/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/" style="font-size: 13px;">多线程</a> <a href="/Skyung/tags/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/" style="font-size: 13.33px;">并发编程</a> <a href="/Skyung/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" style="font-size: 13.67px;">设计模式</a> <a href="/Skyung/tags/%E9%9B%B6%E6%95%A3%E7%82%B9/" style="font-size: 13px;">零散点</a>
    </div>
  </div>

    
      
  <div class="widget">
    <h3 class="widget-title">归档</h3>
    <div class="widget-body">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/Skyung/archives/2022/05/">五月 2022</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/Skyung/archives/2022/04/">四月 2022</a><span class="archive-list-count">7</span></li><li class="archive-list-item"><a class="archive-list-link" href="/Skyung/archives/2022/03/">三月 2022</a><span class="archive-list-count">9</span></li><li class="archive-list-item"><a class="archive-list-link" href="/Skyung/archives/2022/02/">二月 2022</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/Skyung/archives/2021/09/">九月 2021</a><span class="archive-list-count">1</span></li></ul>
    </div>
  </div>


    
      
  <div class="widget">
    <h3 class="widget-title">最新文章</h3>
    <div class="widget-body">
      <ul class="recent-post-list list-unstyled no-thumbnail">
        
          <li>
            
            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/Skyung/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">学习笔记</a>
              </p>
              <p class="item-title">
                <a href="/Skyung/2022/05/08/Spring/" class="title">spring</a>
              </p>
              <p class="item-date">
                <time datetime="2022-05-07T16:00:00.000Z" itemprop="datePublished">2022-05-08</time>
              </p>
            </div>
          </li>
          
          <li>
            
            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/Skyung/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">学习笔记</a>
              </p>
              <p class="item-title">
                <a href="/Skyung/2022/05/08/netty-RPC/" class="title">Netty-RPC</a>
              </p>
              <p class="item-date">
                <time datetime="2022-05-07T16:00:00.000Z" itemprop="datePublished">2022-05-08</time>
              </p>
            </div>
          </li>
          
          <li>
            
            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/Skyung/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">学习笔记</a>
              </p>
              <p class="item-title">
                <a href="/Skyung/2022/05/07/%E5%B8%B8%E7%94%A8%E7%B1%BB%E5%BA%93%E5%92%8CAPI/" class="title">常见类库</a>
              </p>
              <p class="item-date">
                <time datetime="2022-05-06T16:00:00.000Z" itemprop="datePublished">2022-05-07</time>
              </p>
            </div>
          </li>
          
          <li>
            
            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/Skyung/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">学习笔记</a>
              </p>
              <p class="item-title">
                <a href="/Skyung/2022/05/07/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/" class="title">单元测试</a>
              </p>
              <p class="item-date">
                <time datetime="2022-05-06T16:00:00.000Z" itemprop="datePublished">2022-05-07</time>
              </p>
            </div>
          </li>
          
          <li>
            
            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/Skyung/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">学习笔记</a>
              </p>
              <p class="item-title">
                <a href="/Skyung/2022/05/01/netty%E8%81%8A%E5%A4%A9%E5%AE%A4/" class="title">Netty聊天室</a>
              </p>
              <p class="item-date">
                <time datetime="2022-04-30T16:00:00.000Z" itemprop="datePublished">2022-05-01</time>
              </p>
            </div>
          </li>
          
      </ul>
    </div>
  </div>
  

    
  </div>
</aside>

  
  
  <aside class="sidebar sidebar-toc collapse   in  " id="collapseToc" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    <nav id="toc" class="article-toc">
      <h3 class="toc-title">文章目录</h3>
      <ol class="toc"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%A8%A1%E6%9D%BF%E6%A8%A1%E5%BC%8F"><span class="toc-number">1.</span> <span class="toc-text">模板模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F"><span class="toc-number">2.</span> <span class="toc-text">命令模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%AE%BF%E9%97%AE%E8%80%85%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.</span> <span class="toc-text">访问者模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F"><span class="toc-number">4.</span> <span class="toc-text">迭代器模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F"><span class="toc-number">5.</span> <span class="toc-text">观察者模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%AD%E4%BB%8B%E8%80%85%E6%A8%A1%E5%BC%8F"><span class="toc-number">6.</span> <span class="toc-text">中介者模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A4%87%E5%BF%98%E5%BD%95%E6%A8%A1%E5%BC%8F"><span class="toc-number">7.</span> <span class="toc-text">备忘录模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%A3%E9%87%8A%E5%99%A8%E6%A8%A1%E5%BC%8F"><span class="toc-number">8.</span> <span class="toc-text">解释器模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F"><span class="toc-number">9.</span> <span class="toc-text">状态模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F"><span class="toc-number">10.</span> <span class="toc-text">策略模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%81%8C%E8%B4%A3%E9%93%BE%E6%A8%A1%E5%BC%8F"><span class="toc-number">11.</span> <span class="toc-text">职责链模式</span></a></li></ol>
    </nav>
  </div>
</aside>

<main class="main" role="main">
  <div class="content">
  <article id="post-设计模式—行为型模式" class="article article-type-post" itemscope itemtype="http://schema.org/BlogPosting">
    
    <div class="article-header">
      
        
  
    <h1 class="article-title" itemprop="name">
      设计模式—行为型模式
    </h1>
  

      
      <div class="article-meta">
        <span class="article-date">
    <i class="icon icon-calendar-check"></i>
	<a href="/Skyung/2022/03/01/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E2%80%94%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/" class="article-date">
	  <time datetime="2022-02-28T16:00:00.000Z" itemprop="datePublished">2022-03-01</time>
	</a>
</span>
        
  <span class="article-category">
    <i class="icon icon-folder"></i>
    <a class="article-category-link" href="/Skyung/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">学习笔记</a>
  </span>

        
  <span class="article-tag">
    <i class="icon icon-tags"></i>
	<a class="article-tag-link-link" href="/Skyung/tags/java/" rel="tag">java</a>, <a class="article-tag-link-link" href="/Skyung/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" rel="tag">设计模式</a>
  </span>


        

        <span class="post-comment"><i class="icon icon-comment"></i> <a href="/Skyung/2022/03/01/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E2%80%94%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/#comments" class="article-comment-link">评论</a></span>
        
      </div>
    </div>
    <div class="article-entry marked-body" itemprop="articleBody">
      
        <p>行为型模式：类和对象如何交互，及划分责任和算法。模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式（Interpreter模式）、状态模式、策略模式、职责链模式(责任链模式)。</p>
<h3 id="模板模式"><a href="#模板模式" class="headerlink" title="模板模式"></a>模板模式</h3><p>模板方法模式（Template Method Pattern），又叫模板模式(Template Pattern)，在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现，但调用将以抽象类中定义的方式进行。</p>
<p>简单说，模板方法模式定义一个操作中的算法的骨架，而将一些步骤延迟到子类中，使得子类可以不改变一个算法的结构，就可以重定义该算法的某些特定步骤。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">AbstractClass</span> &#123;</span><br><span class="line">	<span class="comment">//基本方法</span></span><br><span class="line">	<span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">doSomething</span><span class="params">()</span>;</span><br><span class="line">	<span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">doAnything</span><span class="params">()</span>;</span><br><span class="line">	<span class="comment">//模板方法</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">templateMethod</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="comment">//调用基本方法，完成相关的逻辑</span></span><br><span class="line">		<span class="built_in">this</span>.doAnything();</span><br><span class="line">		<span class="built_in">this</span>.doSomething();</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"> <span class="comment">//具体实现类就不写了……</span></span><br></pre></td></tr></table></figure>

<p>模板方法很简单，仅仅使用了java的继承机制，但是它是一个应用非常广泛的模式，其中AbstractClass叫做抽象模板，它的方法分为两类：<strong>基本方法（由子类去实现）和模板方法</strong>（可以有一个或多个，也就是一个框架，实现对基本方法的调度，完成固定的逻辑）。为了防止恶意的操作，一般模板方法上都添加上final关键字，不允许被覆写。</p>
<p><strong>模板方法的钩子方法：</strong></p>
<p>模板方法中的某些方法可能不需要默认就执行，在实现类中定义一个判断标记，然后对外提供一个public接口set来让外界设置这个判断标记，这就像是开关一样，想让它ture和false都行。这个isDoSomething方法俗称钩子方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">AbstractClass</span> &#123;</span><br><span class="line">	<span class="comment">//基本方法</span></span><br><span class="line">	<span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">doSomething</span><span class="params">()</span>;</span><br><span class="line">	<span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">doAnything</span><span class="params">()</span>;</span><br><span class="line">	<span class="comment">//模板方法</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">templateMethod</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="comment">//调用基本方法，完成相关的逻辑</span></span><br><span class="line">        <span class="keyword">if</span>(<span class="built_in">this</span>.isDoSomething()) &#123;<span class="comment">//想让它叫就叫，不想就不叫		</span></span><br><span class="line">			<span class="built_in">this</span>.doSomething();</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="built_in">this</span>.doAnything();</span><br><span class="line">	&#125;</span><br><span class="line">    <span class="keyword">protected</span> <span class="type">boolean</span> <span class="title function_">isDoSomething</span><span class="params">()</span>&#123; <span class="comment">//加了一个判断方法，默认返回true</span></span><br><span class="line">		<span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Class1</span> <span class="keyword">extends</span> <span class="title class_">AbstractClass</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">boolean</span> <span class="variable">doSomethingFlag</span> <span class="operator">=</span> <span class="literal">false</span>; <span class="comment">//判断标记</span></span><br><span class="line">    <span class="comment">//重写抽象方法</span></span><br><span class="line">    ...</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">protected</span> <span class="type">boolean</span> <span class="title function_">isDoSomething</span><span class="params">()</span> &#123; <span class="comment">//覆写isDoSomething方法，返回判断标记</span></span><br><span class="line">		<span class="keyword">return</span> <span class="built_in">this</span>.doSomethingFlag;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>源码</strong></p>
<p>Spring IOC容器初始化时运用到的模板方法模式</p>
<p>AbstractApplicationContext类中：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">refresh</span><span class="params">()</span> <span class="keyword">throws</span> BeansException, IllegalStateException &#123;</span><br><span class="line">        <span class="keyword">synchronized</span>(<span class="built_in">this</span>.startupShutdownMonitor) &#123;</span><br><span class="line">            <span class="built_in">this</span>.prepareRefresh();</span><br><span class="line">            <span class="type">ConfigurableListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> <span class="built_in">this</span>.obtainFreshBeanFactory();</span><br><span class="line">            <span class="built_in">this</span>.prepareBeanFactory(beanFactory);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="built_in">this</span>.postProcessBeanFactory(beanFactory);</span><br><span class="line">                <span class="built_in">this</span>.invokeBeanFactoryPostProcessors(beanFactory);</span><br><span class="line">                <span class="built_in">this</span>.registerBeanPostProcessors(beanFactory);</span><br><span class="line">                <span class="built_in">this</span>.initMessageSource();</span><br><span class="line">                <span class="built_in">this</span>.initApplicationEventMulticaster();</span><br><span class="line">                <span class="built_in">this</span>.onRefresh();</span><br><span class="line">                <span class="built_in">this</span>.registerListeners();</span><br><span class="line">                <span class="built_in">this</span>.finishBeanFactoryInitialization(beanFactory);</span><br><span class="line">                <span class="built_in">this</span>.finishRefresh();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (BeansException var9) &#123;</span><br><span class="line">                <span class="keyword">if</span> (<span class="built_in">this</span>.logger.isWarnEnabled()) &#123;</span><br><span class="line">                    <span class="built_in">this</span>.logger.warn(<span class="string">&quot;Exception encountered during context initialization - cancelling refresh attempt: &quot;</span> + var9);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="built_in">this</span>.destroyBeans();</span><br><span class="line">                <span class="built_in">this</span>.cancelRefresh(var9);</span><br><span class="line">                <span class="keyword">throw</span> var9;</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                <span class="built_in">this</span>.resetCommonCaches();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p><strong>小结</strong></p>
<p>模板方法模式的基本思想是：算法只存在于一个地方，也就是在父类中，容易修改。需要修改算法时，只要修改父类的模板方法或者已经实现的某些步骤，子类就会继承这些修改。</p>
<p>一般模板方法都加上final关键字，防止子类重写模板方法。</p>
<p>模板方法模式使用场景：当要完成在某个过程，该过程要执行一系列步骤 ，这一 系列的步骤基本相同，但其个别步骤在实现时可能不同，通常考虑用模板方法模式来处理。</p>
<h3 id="命令模式"><a href="#命令模式" class="headerlink" title="命令模式"></a>命令模式</h3><p>命令模式（Command Pattern）：在软件设计中，经常需要向某些对象发送请求，但是并不知道请求的接收者是谁，也不知道被请求的操作是哪个，只需在程序运行时指定具体的请求接收者即可，此时，可以使用命令模式来进行设计。</p>
<p><strong>命名模式使得请求发送者与请求接收者消除彼此之间的耦合，让对象之间的调用关系更加灵活，实现解耦。</strong></p>
<p>在命名模式中，会将一个请求封装为一个对象，以便使用不同参数来表示不同的请求，同时命令模式也支持可撤销的操作。</p>
<p>命令模式分为：</p>
<p>Invoker 是调用者角色；</p>
<p>Command: 是命令角色，需要执行的所有命令都在这里，可以是接口或抽象类；</p>
<p>Receiver: 接受者角色，知道如何实施和执行一个请求相关的操作；</p>
<p>ConcreteCommand: 将一个接受者对象与一个动作绑定，调用接受者相应的操作，实现execute。</p>
<p><img src="https://gitee.com/lifuh/picgo/raw/master/img/image-20220301172207826.png" alt="image-20220301172207826"></p>
<p>代码举例：有个遥控器，有几组开关和撤销按钮，可以控制灯等不同的电器。</p>
<p>命令的接口：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Command</span> &#123;</span><br><span class="line">   <span class="comment">//执行动作(操作)</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">execute</span><span class="params">()</span>;</span><br><span class="line">   <span class="comment">//撤销动作(操作)</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">undo</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>接收者：控制电灯的开关</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LightReceiver</span> &#123;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">on</span><span class="params">()</span> &#123;</span><br><span class="line">      System.out.println(<span class="string">&quot; 电灯打开了.. &quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">off</span><span class="params">()</span> &#123;</span><br><span class="line">      System.out.println(<span class="string">&quot; 电灯关闭了.. &quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>将接受者对象与一个动作绑定</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LightOnCommand</span> <span class="keyword">implements</span> <span class="title class_">Command</span> &#123;</span><br><span class="line">	<span class="comment">//聚合LightReceiver</span></span><br><span class="line">	LightReceiver light;</span><br><span class="line">	<span class="comment">//构造器</span></span><br><span class="line">	<span class="keyword">public</span> <span class="title function_">LightOnCommand</span><span class="params">(LightReceiver light)</span> &#123;</span><br><span class="line">		<span class="built_in">super</span>();</span><br><span class="line">		<span class="built_in">this</span>.light = light;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">execute</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="comment">//调用接收者的方法</span></span><br><span class="line">		light.on();</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">undo</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="comment">//调用接收者的方法</span></span><br><span class="line">		light.off();</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LightOffCommand</span> <span class="keyword">implements</span> <span class="title class_">Command</span> &#123;</span><br><span class="line">   LightReceiver light;</span><br><span class="line">   <span class="keyword">public</span> <span class="title function_">LightOffCommand</span><span class="params">(LightReceiver light)</span> &#123;</span><br><span class="line">         <span class="built_in">super</span>();</span><br><span class="line">         <span class="built_in">this</span>.light = light;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">execute</span><span class="params">()</span> &#123;</span><br><span class="line">      light.off();</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">undo</span><span class="params">()</span> &#123;</span><br><span class="line">      light.on();</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//空命令，可用于初始化</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NoCommand</span> <span class="keyword">implements</span> <span class="title class_">Command</span> &#123;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">execute</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="comment">// TODO Auto-generated method stub	</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">undo</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="comment">// TODO Auto-generated method stub</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Invoker调用者：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RemoteController</span> &#123;</span><br><span class="line"></span><br><span class="line">   <span class="comment">// 开按钮的命令数组</span></span><br><span class="line">   Command[] onCommands;</span><br><span class="line">   Command[] offCommands;</span><br><span class="line">   <span class="comment">// 执行撤销的命令</span></span><br><span class="line">   Command undoCommand;</span><br><span class="line"></span><br><span class="line">   <span class="comment">// 构造器，完成对按钮初始化</span></span><br><span class="line">   <span class="keyword">public</span> <span class="title function_">RemoteController</span><span class="params">()</span> &#123;</span><br><span class="line">       <span class="comment">//假设有五组开关</span></span><br><span class="line">      onCommands = <span class="keyword">new</span> <span class="title class_">Command</span>[<span class="number">5</span>];</span><br><span class="line">      offCommands = <span class="keyword">new</span> <span class="title class_">Command</span>[<span class="number">5</span>];</span><br><span class="line">		<span class="comment">//初始化</span></span><br><span class="line">      <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">         onCommands[i] = <span class="keyword">new</span> <span class="title class_">NoCommand</span>();</span><br><span class="line">         offCommands[i] = <span class="keyword">new</span> <span class="title class_">NoCommand</span>();</span><br><span class="line">      &#125;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">// 给按钮设置你需要的命令</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setCommand</span><span class="params">(<span class="type">int</span> no, Command onCommand, Command offCommand)</span> &#123;</span><br><span class="line">      onCommands[no] = onCommand;</span><br><span class="line">      offCommands[no] = offCommand;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">// 按下开按钮</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onButtonWasPushed</span><span class="params">(<span class="type">int</span> no)</span> &#123; <span class="comment">// no 0</span></span><br><span class="line">      <span class="comment">// 找到你按下的开的按钮， 并调用对应方法</span></span><br><span class="line">      onCommands[no].execute();</span><br><span class="line">      <span class="comment">// 记录这次的操作，用于撤销</span></span><br><span class="line">      undoCommand = onCommands[no];</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="comment">// 按下关按钮</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">offButtonWasPushed</span><span class="params">(<span class="type">int</span> no)</span> &#123; <span class="comment">// no 0</span></span><br><span class="line">      <span class="comment">// 找到你按下的关的按钮， 并调用对应方法</span></span><br><span class="line">      offCommands[no].execute();</span><br><span class="line">      <span class="comment">// 记录这次的操作，用于撤销</span></span><br><span class="line">      undoCommand = offCommands[no];</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">// 按下撤销按钮</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">undoButtonWasPushed</span><span class="params">()</span> &#123;</span><br><span class="line">      undoCommand.undo();</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>客户端调用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Client</span> &#123;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123; </span><br><span class="line">      <span class="comment">//创建电灯的对象(接受者)</span></span><br><span class="line">      <span class="type">LightReceiver</span> <span class="variable">lightReceiver</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">LightReceiver</span>();</span><br><span class="line">      <span class="comment">//创建电灯相关的开关命令</span></span><br><span class="line">      <span class="type">LightOnCommand</span> <span class="variable">lightOnCommand</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">LightOnCommand</span>(lightReceiver);</span><br><span class="line">      <span class="type">LightOffCommand</span> <span class="variable">lightOffCommand</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">LightOffCommand</span>(lightReceiver);</span><br><span class="line">      <span class="comment">//需要一个遥控器</span></span><br><span class="line">      <span class="type">RemoteController</span> <span class="variable">remoteController</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">RemoteController</span>();</span><br><span class="line">      <span class="comment">//给我们的遥控器设置命令, 比如 no = 0 是电灯的开和关的操作</span></span><br><span class="line">      remoteController.setCommand(<span class="number">0</span>, lightOnCommand, lightOffCommand);</span><br><span class="line">      System.out.println(<span class="string">&quot;--------按下灯的开按钮-----------&quot;</span>);</span><br><span class="line">      remoteController.onButtonWasPushed(<span class="number">0</span>);</span><br><span class="line">      System.out.println(<span class="string">&quot;--------按下灯的关按钮-----------&quot;</span>);</span><br><span class="line">      remoteController.offButtonWasPushed(<span class="number">0</span>);</span><br><span class="line">      System.out.println(<span class="string">&quot;--------按下撤销按钮-----------&quot;</span>);</span><br><span class="line">      remoteController.undoButtonWasPushed();</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>扩展到电视机：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TVReceiver</span> &#123;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">on</span><span class="params">()</span> &#123;</span><br><span class="line">      System.out.println(<span class="string">&quot; 电视机打开了.. &quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">off</span><span class="params">()</span> &#123;</span><br><span class="line">      System.out.println(<span class="string">&quot; 电视机关闭了.. &quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TVOnCommand</span> <span class="keyword">implements</span> <span class="title class_">Command</span> &#123;</span><br><span class="line">	TVReceiver tv;</span><br><span class="line">	<span class="keyword">public</span> <span class="title function_">TVOnCommand</span><span class="params">(TVReceiver tv)</span> &#123;</span><br><span class="line">		<span class="built_in">super</span>();</span><br><span class="line">		<span class="built_in">this</span>.tv = tv;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">execute</span><span class="params">()</span> &#123;</span><br><span class="line">		tv.on();</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">undo</span><span class="params">()</span> &#123;</span><br><span class="line">		tv.off();</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//同样的TVOffCommand</span></span><br></pre></td></tr></table></figure>

<p><strong>源码</strong></p>
<p>典型的java.lang.Runable和线程池中都有用到命令模式。</p>
<p>Runable：任务抽象，也就是“命令”；线程池通过submit和execute调用。</p>
<p><strong>小结：</strong></p>
<p>将发起请求的对象与执行请求的对象解耦；（也就是中间加了一层，命令类）</p>
<p>容易设计一个命令队列。只要把命令对象放到列队，就可以多线程的执行命令；</p>
<p>命令模式不足：可能导致某些系统有过多的具体命令类，增加了系统的复杂度，这 点在在使用的时候要注意。</p>
<h3 id="访问者模式"><a href="#访问者模式" class="headerlink" title="访问者模式"></a>访问者模式</h3><p>访问者模式（Visitor Pattern），封装一些作用于某种数据结构的各元素的操作，它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。</p>
<p>主要将数据结构与数据操作分离，解决数据结构和操作耦合性问题。</p>
<p>访问者模式的基本工作原理是：在被访问的类里面加一个对外提供接待访问者的接口。</p>
<p>访问者模式主要应用场景是：需要对一个对象结构中的对象进行很多不同操作 (这些操作彼此没有关联)，同时需要避免让这些操作”污染”这些对象的类，可以选用访问者模式解决。</p>
<p>访问者模式分为：</p>
<p>Visitor 是抽象访问者，为该对象结构中的ConcreteElement的每一个类声明一个visit操作。</p>
<p>ConcreteVisitor ：是一个具体的访问者，实现每个有Visitor 声明的操作，是每个操作实现的部分。</p>
<p>ObjectStructure 能枚举它的元素， 可以提供一个高层的接口，用来允许访问者访问元素。</p>
<p>Element 定义一个accept 方法，接收一个访问者对象。</p>
<p>ConcreteElement 为具体元素，实现了accept 方法。</p>
<p><img src="https://gitee.com/lifuh/picgo/raw/master/img/webp.png"></p>
<p>案例代码实现：</p>
<p>年底，CEO和CTO开始评定员工一年的工作绩效，员工分为工程师和经理，CTO关注工程师的代码量、经理的新产品数量；CEO关注的是工程师的KPI和经理的KPI以及新产品数量。由于CEO和CTO对于不同员工的关注点是不一样的，这就需要对不同员工类型进行不同的处理。访问者模式此时可以派上用场了。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//被访问者Element：员工基类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">Staff</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> String name;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> kpi;<span class="comment">// 员工KPI</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Staff</span><span class="params">(String name)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">        kpi = <span class="keyword">new</span> <span class="title class_">Random</span>().nextInt(<span class="number">10</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 核心方法，接受Visitor的访问</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">accept</span><span class="params">(Visitor visitor)</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 工程师</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Engineer</span> <span class="keyword">extends</span> <span class="title class_">Staff</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Engineer</span><span class="params">(String name)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(name);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">accept</span><span class="params">(Visitor visitor)</span> &#123;</span><br><span class="line">        visitor.visit(<span class="built_in">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 工程师一年的代码数量</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getCodeLines</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Random</span>().nextInt(<span class="number">10</span> * <span class="number">10000</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 经理</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Manager</span> <span class="keyword">extends</span> <span class="title class_">Staff</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Manager</span><span class="params">(String name)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(name);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">accept</span><span class="params">(Visitor visitor)</span> &#123;</span><br><span class="line">        visitor.visit(<span class="built_in">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 一年做的产品数量</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getProducts</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Random</span>().nextInt(<span class="number">10</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>工程师是代码数量，经理是产品数量，他们的职责不一样，也就是因为差异性，才使得访问模式能够发挥它的作用。Staff、Engineer、Manager 3个类型就是<strong>对象结构，这些类型相对稳定</strong>，不会发生变化。</p>
<p><strong>visitor.visit(this)使用到了双分派，首先将Visitor作为参数传给Staff，然后又将Staff自己本身作为参数传给Visitor，解耦的关键。</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//ObjectStructure：能枚举被访问者元素</span></span><br><span class="line"><span class="comment">//这些员工添加到一个业务报表类中</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BusinessReport</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> List&lt;Staff&gt; mStaffs = <span class="keyword">new</span> <span class="title class_">LinkedList</span>&lt;&gt;();</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">BusinessReport</span><span class="params">()</span> &#123;</span><br><span class="line">        mStaffs.add(<span class="keyword">new</span> <span class="title class_">Manager</span>(<span class="string">&quot;经理-A&quot;</span>));</span><br><span class="line">        mStaffs.add(<span class="keyword">new</span> <span class="title class_">Engineer</span>(<span class="string">&quot;工程师-A&quot;</span>));</span><br><span class="line">        mStaffs.add(<span class="keyword">new</span> <span class="title class_">Engineer</span>(<span class="string">&quot;工程师-B&quot;</span>));</span><br><span class="line">        mStaffs.add(<span class="keyword">new</span> <span class="title class_">Engineer</span>(<span class="string">&quot;工程师-C&quot;</span>));</span><br><span class="line">        mStaffs.add(<span class="keyword">new</span> <span class="title class_">Manager</span>(<span class="string">&quot;经理-B&quot;</span>));</span><br><span class="line">        mStaffs.add(<span class="keyword">new</span> <span class="title class_">Engineer</span>(<span class="string">&quot;工程师-D&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="comment">//可以提供一个高层的接口，用来允许访问者访问元素。</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">showReport</span><span class="params">(Visitor visitor)</span> &#123;</span><br><span class="line">        <span class="keyword">for</span> (Staff staff : mStaffs) &#123;</span><br><span class="line">            staff.accept(visitor);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p> Visitor访问者接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//对于 Engineer、Manager 的访问会调用两个不同的方法，以此达成区别对待、差异化处理</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Visitor</span> &#123;</span><br><span class="line">    <span class="comment">// 访问工程师类型</span></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">visit</span><span class="params">(Engineer engineer)</span>;</span><br><span class="line">    <span class="comment">// 访问经理类型</span></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">visit</span><span class="params">(Manager manager)</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// CEO访问者</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CEOVisitor</span> <span class="keyword">implements</span> <span class="title class_">Visitor</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">visit</span><span class="params">(Engineer engineer)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;工程师: &quot;</span> + engineer.name + <span class="string">&quot;, KPI: &quot;</span> + engineer.kpi);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">visit</span><span class="params">(Manager manager)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;经理: &quot;</span> + manager.name + <span class="string">&quot;, KPI: &quot;</span> + manager.kpi +</span><br><span class="line">                <span class="string">&quot;, 新产品数量: &quot;</span> + manager.getProducts());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CTOVisitor</span> <span class="keyword">implements</span> <span class="title class_">Visitor</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">visit</span><span class="params">(Engineer engineer)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;工程师: &quot;</span> + engineer.name + <span class="string">&quot;, 代码行数: &quot;</span> + engineer.getCodeLines());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">visit</span><span class="params">(Manager manager)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;经理: &quot;</span> + manager.name + <span class="string">&quot;, 产品数量: &quot;</span> + manager.getProducts());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上面的代码通过两个 visitor 方法分别进行处理。如果不使用 Visitor 模式，只通过一个 visit 方法进行处理，那么就需要在这个 visit 方法中进行判断，然后分别处理，代码大致如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ReportUtil</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">visit</span><span class="params">(Staff staff)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (staff <span class="keyword">instanceof</span> Manager) &#123;</span><br><span class="line">            <span class="type">Manager</span> <span class="variable">manager</span> <span class="operator">=</span> (Manager) staff;</span><br><span class="line">            System.out.println(<span class="string">&quot;经理: &quot;</span> + manager.name + <span class="string">&quot;, KPI: &quot;</span> + manager.kpi +</span><br><span class="line">                    <span class="string">&quot;, 新产品数量: &quot;</span> + manager.getProducts());</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (staff <span class="keyword">instanceof</span> Engineer) &#123;</span><br><span class="line">            <span class="type">Engineer</span> <span class="variable">engineer</span> <span class="operator">=</span> (Engineer) staff;</span><br><span class="line">            System.out.println(<span class="string">&quot;工程师: &quot;</span> + engineer.name + <span class="string">&quot;, KPI: &quot;</span> + engineer.kpi);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这就导致了 <strong>if-else 逻辑的嵌套以及类型的强制转换，难以扩展和维护</strong>。也不符合单一职责原则，增加员工类型又要修改代码，不符合开闭原则。</p>
<p>客户端访问：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Client</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">// 构建报表</span></span><br><span class="line">        <span class="type">BusinessReport</span> <span class="variable">report</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BusinessReport</span>();</span><br><span class="line">        System.out.println(<span class="string">&quot;=========== CEO看报表 ===========&quot;</span>);</span><br><span class="line">        report.showReport(<span class="keyword">new</span> <span class="title class_">CEOVisitor</span>());</span><br><span class="line">        System.out.println(<span class="string">&quot;=========== CTO看报表 ===========&quot;</span>);</span><br><span class="line">        report.showReport(<span class="keyword">new</span> <span class="title class_">CTOVisitor</span>());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>访问者模式最大的优点就是增加访问者非常容易，从代码中可以看到，如果要增加一个访问者，只要新实现一个 Visitor 接口的类，从而达到数据对象与数据操作相分离的效果。</p>
<p><strong>最关键的就是双分派。</strong></p>
<p>小结：</p>
<p>访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高。</p>
<p>缺点：具体元素对访问者公布细节，也就是说访问者关注了其他类的内部细节，这是迪米特法则所不建议的，这样造成了具体元素变更比较困难；违背了依赖倒转原则。访问者依赖的是具体元素，而不是抽象元素。</p>
<h3 id="迭代器模式"><a href="#迭代器模式" class="headerlink" title="迭代器模式"></a>迭代器模式</h3><p>迭代器模式（Iterator Pattern），提供一种遍历集合元素的统一接口，用一致的方法遍历集合元素， 不需要知道集合对象的底层表示，即：不暴露其内部的结构。</p>
<p>当<strong>集合元素是用不同的方式实现的</strong>，有数组，还有java的集合类，或者还有其他方式，当客户端要遍历这些集合元素的时候就要使用多种遍历方式，而且还会暴露元素的内部结构，可以考虑使用迭代器模式解决。</p>
<p>迭代器模式包括：</p>
<p>Iterator ： 迭代器接口，含有：hasNext, next, remove。</p>
<p>ConcreteIterator : 具体的迭代器类，管理迭代；</p>
<p>Aggregate：一个统一的聚合接口，将客户端和具体聚合解耦，接口中声明的方法为iterator,作用为生成一个用于遍历的迭代器。</p>
<p>ConcreteAggregate：具体的聚合持有对象的接口。</p>
<p>案例代码：</p>
<p>上层接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Aggregate 接口，所要便利的集合的接口。实现了该接口的类将成为一个可以保存多个元素的集合，类似数组。</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Aggregate</span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> Iterator <span class="title function_">iterator</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//Iterator 接口</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Iterator</span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="type">boolean</span> <span class="title function_">hasNext</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> Object <span class="title function_">next</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>要迭代的具体元素</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Book</span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name ;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Book</span><span class="params">(String name)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.name=name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getName</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Aggregate 和Iterator具体实现类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//书架，作为存放书的集合类，实现了Aggregate接口的iterator方法。</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookShelf</span> <span class="keyword">implements</span> <span class="title class_">Aggregate</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> List&lt;Book&gt; books;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">BookShelf</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.books = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;Book&gt;();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> Book <span class="title function_">getBookAt</span><span class="params">(<span class="type">int</span> index)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> books.get(index);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">appendBook</span><span class="params">(Book book)</span> &#123;</span><br><span class="line">        books.add(book);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getLength</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> books.size();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> Iterator <span class="title function_">iterator</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">BookShelfIterator</span>(<span class="built_in">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//BookShelfIterator类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookShelfIterator</span> <span class="keyword">implements</span> <span class="title class_">Iterator</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> BookShelf bookShelf;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> index;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">BookShelfIterator</span><span class="params">(BookShelf bookShelf)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bookShelf = bookShelf;</span><br><span class="line">        <span class="built_in">this</span>.index = <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">hasNext</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (index &lt; bookShelf.getLength()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">next</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">Book</span> <span class="variable">book</span> <span class="operator">=</span> bookShelf.getBookAt(index);</span><br><span class="line">        index++;</span><br><span class="line">        <span class="keyword">return</span> book;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>客户端调用</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">BookShelf</span> <span class="variable">bookShelf</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BookShelf</span>();</span><br><span class="line">        bookShelf.appendBook(<span class="keyword">new</span> <span class="title class_">Book</span>(<span class="string">&quot;Around the World in 80 Days&quot;</span>));</span><br><span class="line">        bookShelf.appendBook(<span class="keyword">new</span> <span class="title class_">Book</span>(<span class="string">&quot;Bible&quot;</span>));</span><br><span class="line">        bookShelf.appendBook(<span class="keyword">new</span> <span class="title class_">Book</span>(<span class="string">&quot;Cinderella&quot;</span>));</span><br><span class="line">        bookShelf.appendBook(<span class="keyword">new</span> <span class="title class_">Book</span>(<span class="string">&quot;Daddy-Long-Legs&quot;</span>));</span><br><span class="line">        <span class="type">Iterator</span> <span class="variable">it</span> <span class="operator">=</span> bookShelf.iterator();</span><br><span class="line">        <span class="keyword">while</span> (it.hasNext()) &#123;</span><br><span class="line">            <span class="type">Book</span> <span class="variable">book</span> <span class="operator">=</span> (Book) it.next();</span><br><span class="line">            System.out.println(book.getName());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果需要扩展，只需要新的类实现Aggregate 和Iterator。</p>
<p><strong>源码</strong></p>
<p>JDK的ArrayList 集合中就使用了迭代器模式</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//存放数据的方式</span></span><br><span class="line"><span class="keyword">transient</span> Object[] elementData;</span><br><span class="line"><span class="comment">//获取一个迭代器</span></span><br><span class="line"><span class="keyword">public</span> Iterator&lt;E&gt; <span class="title function_">iterator</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Itr</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//Itr是ArrayList的内部类</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">class</span> <span class="title class_">Itr</span> <span class="keyword">implements</span> <span class="title class_">Iterator</span>&lt;E&gt; &#123;</span><br><span class="line">    ...</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">hasNext</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> cursor != size;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@SuppressWarnings(&quot;unchecked&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> E <span class="title function_">next</span><span class="params">()</span> &#123;</span><br><span class="line">        checkForComodification();</span><br><span class="line">        <span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> cursor;</span><br><span class="line">        <span class="keyword">if</span> (i &gt;= size)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NoSuchElementException</span>();</span><br><span class="line">        Object[] elementData = ArrayList.<span class="built_in">this</span>.elementData;</span><br><span class="line">        <span class="keyword">if</span> (i &gt;= elementData.length)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ConcurrentModificationException</span>();</span><br><span class="line">        cursor = i + <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">return</span> (E) elementData[lastRet = i];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>角色分析</p>
<p>内部类Itr 充当具体实现迭代器Iterator 的类， 作为ArrayList 内部类。</p>
<p>List 就是充当了聚合接口，含有一个iterator() 方法，返回一个迭代器对象。</p>
<p>ArrayList 是实现聚合接口List 的子类，实现了iterator()。</p>
<p>迭代器模式解决了 不同集合(ArrayList ,LinkedList) 统一遍历问题。</p>
<p><strong>小结：</strong></p>
<p>提供了一种设计思想，就是一个类应该只有一个引起变化的原因（叫做单一责任 原则）。在聚合类中，把迭代器分开，就是要<strong>把管理对象集合和遍历对象集合的责任分开</strong>，这样一来集合改变的话，只影响到聚合对象。而如果遍历方式改变 的话，只影响到了迭代器。</p>
<h3 id="观察者模式"><a href="#观察者模式" class="headerlink" title="观察者模式"></a>观察者模式</h3><p>有一个实际场景案例：天气预报项目，气象站可以将每天测量到的温度，湿度，气压等等以公告的形式发布出去（发布到不同的网站），测量数据更新时，要能实时的通知给第三方。</p>
<p>传统的设计方案：</p>
<p>设计WeatherData类，通过getXxx方法，可以让第三方接入，并得到相关信息，当数据有更新时，气象站通过调用dataChange() 去更新数据。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//气象站方</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WeatherData</span> &#123;</span><br><span class="line">   <span class="keyword">private</span> <span class="type">float</span> temperatrue;</span><br><span class="line">   <span class="keyword">private</span> <span class="type">float</span> pressure;</span><br><span class="line">   <span class="keyword">private</span> <span class="type">float</span> humidity;</span><br><span class="line">   <span class="comment">//可以看作是某个天气网站，接入气象站</span></span><br><span class="line">   <span class="keyword">private</span> CurrentConditions currentConditions;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">public</span> <span class="title function_">WeatherData</span><span class="params">(CurrentConditions currentConditions)</span> &#123;</span><br><span class="line">      <span class="built_in">this</span>.currentConditions = currentConditions;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">public</span> <span class="type">float</span> <span class="title function_">getTemperature</span><span class="params">()</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> temperatrue;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">public</span> <span class="type">float</span> <span class="title function_">getPressure</span><span class="params">()</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> pressure;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">public</span> <span class="type">float</span> <span class="title function_">getHumidity</span><span class="params">()</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> humidity;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">dataChange</span><span class="params">()</span> &#123;</span><br><span class="line">      <span class="comment">//调用接入方的 update</span></span><br><span class="line">      currentConditions.update(getTemperature(), getPressure(), getHumidity());</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">//当数据有更新时，就调用 setData</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setData</span><span class="params">(<span class="type">float</span> temperature, <span class="type">float</span> pressure, <span class="type">float</span> humidity)</span> &#123;</span><br><span class="line">      <span class="built_in">this</span>.temperatrue = temperature;</span><br><span class="line">      <span class="built_in">this</span>.pressure = pressure;</span><br><span class="line">      <span class="built_in">this</span>.humidity = humidity;</span><br><span class="line">      <span class="comment">//调用dataChange， 将最新的信息 推送给 接入方 currentConditions</span></span><br><span class="line">      dataChange();</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//示当前天气情况（可以理解成某个气象网站）</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CurrentConditions</span> &#123;</span><br><span class="line">   <span class="comment">// 温度，气压，湿度</span></span><br><span class="line">   <span class="keyword">private</span> <span class="type">float</span> temperature;</span><br><span class="line">   <span class="keyword">private</span> <span class="type">float</span> pressure;</span><br><span class="line">   <span class="keyword">private</span> <span class="type">float</span> humidity;</span><br><span class="line"></span><br><span class="line">   <span class="comment">//更新天气情况</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">update</span><span class="params">(<span class="type">float</span> temperature, <span class="type">float</span> pressure, <span class="type">float</span> humidity)</span> &#123;</span><br><span class="line">      <span class="built_in">this</span>.temperature = temperature;</span><br><span class="line">      <span class="built_in">this</span>.pressure = pressure;</span><br><span class="line">      <span class="built_in">this</span>.humidity = humidity;</span><br><span class="line">      display();</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">//显示</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">display</span><span class="params">()</span> &#123;</span><br><span class="line">      System.out.println(<span class="string">&quot;***Today mTemperature: &quot;</span> + temperature + <span class="string">&quot;***&quot;</span>);</span><br><span class="line">      System.out.println(<span class="string">&quot;***Today mPressure: &quot;</span> + pressure + <span class="string">&quot;***&quot;</span>);</span><br><span class="line">      System.out.println(<span class="string">&quot;***Today mHumidity: &quot;</span> + humidity + <span class="string">&quot;***&quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上述方案存在的问题：当增加一个气象网站，都需要创建一个对应的气象网站对象，并加入到dataChange, 不利于维护，也不是动态加入。</p>
<p><strong>观察者模式：</strong>对象之间多对一依赖的一种设计方案，被依赖的对象为Subject， 依赖的对象为Observer，Subject通知Observer变化。</p>
<p>被依赖的对象Subject接口存在三个核心方法：registerObserver 注册；removeObserver 移除；notifyObservers() 通知所有的注册的用户。</p>
<p>通过观察者模式改进上面的案例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//接口, 让WeatherData 来实现 </span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Subject</span> &#123;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">registerObserver</span><span class="params">(Observer o)</span>;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">removeObserver</span><span class="params">(Observer o)</span>;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">notifyObservers</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//观察者接口，有观察者来实现</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Observer</span> &#123;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">update</span><span class="params">(<span class="type">float</span> temperature, <span class="type">float</span> pressure, <span class="type">float</span> humidity)</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//具体的被观察者</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WeatherData</span> <span class="keyword">implements</span> <span class="title class_">Subject</span> &#123;</span><br><span class="line">	<span class="keyword">private</span> <span class="type">float</span> temperatrue;</span><br><span class="line">	<span class="keyword">private</span> <span class="type">float</span> pressure;</span><br><span class="line">	<span class="keyword">private</span> <span class="type">float</span> humidity;</span><br><span class="line">	<span class="comment">//观察者集合</span></span><br><span class="line">	<span class="keyword">private</span> ArrayList&lt;Observer&gt; observers;</span><br><span class="line">	<span class="keyword">public</span> <span class="title function_">WeatherData</span><span class="params">()</span> &#123;</span><br><span class="line">		observers = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;Observer&gt;();</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">public</span> <span class="type">float</span> <span class="title function_">getTemperature</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="keyword">return</span> temperatrue;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">public</span> <span class="type">float</span> <span class="title function_">getPressure</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="keyword">return</span> pressure;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">public</span> <span class="type">float</span> <span class="title function_">getHumidity</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="keyword">return</span> humidity;</span><br><span class="line">	&#125;</span><br><span class="line">    <span class="comment">//当数据有更新时，就调用 setData</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setData</span><span class="params">(<span class="type">float</span> temperature, <span class="type">float</span> pressure, <span class="type">float</span> humidity)</span> &#123;</span><br><span class="line">		<span class="built_in">this</span>.temperatrue = temperature;</span><br><span class="line">		<span class="built_in">this</span>.pressure = pressure;</span><br><span class="line">		<span class="built_in">this</span>.humidity = humidity;</span><br><span class="line">		<span class="comment">//调用notifyObservers， 将最新的信息推送给接入方</span></span><br><span class="line">		notifyObservers();</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//注册一个观察者</span></span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">registerObserver</span><span class="params">(Observer o)</span> &#123;</span><br><span class="line">		observers.add(o);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">removeObserver</span><span class="params">(Observer o)</span> &#123;</span><br><span class="line">		<span class="keyword">if</span>(observers.contains(o)) &#123;</span><br><span class="line">			observers.remove(o);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//遍历所有的观察者，并通知</span></span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">notifyObservers</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="keyword">for</span>(<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; observers.size(); i++) &#123;</span><br><span class="line">			observers.get(i).update(<span class="built_in">this</span>.temperatrue, <span class="built_in">this</span>.pressure, <span class="built_in">this</span>.humidity);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//具体的观察者同上，当需要增加新的观察者，只需要实现Observer接口，并registerObserver注册</span></span><br></pre></td></tr></table></figure>

<p><strong>源码</strong></p>
<p>Jdk的Observable类就使用了观察者模式</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//相当于被观察者，其他类可以通过继承来使用</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Observable</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">boolean</span> <span class="variable">changed</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">private</span> Vector&lt;Observer&gt; obs;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title function_">addObserver</span><span class="params">(Observer o)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (o == <span class="literal">null</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line">        <span class="keyword">if</span> (!obs.contains(o)) &#123;</span><br><span class="line">            obs.addElement(o);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">     <span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title function_">deleteObserver</span><span class="params">(Observer o)</span> &#123;</span><br><span class="line">        obs.removeElement(o);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">notifyObservers</span><span class="params">()</span> &#123;</span><br><span class="line">        notifyObservers(<span class="literal">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//观察者接口</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Observer</span> &#123;</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">update</span><span class="params">(Observable o, Object arg)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="中介者模式"><a href="#中介者模式" class="headerlink" title="中介者模式"></a>中介者模式</h3><p>中介者模式（Mediator Pattern），用一个中介对象来封装一系列的对象交互。 中介者使各个对象不需要显式地相互引用，从而使其耦合松散，而且可以独立地改变它们之间的交互。</p>
<p>Mediator是抽象中介者，定义了同事对象到中介者对象的接口；Colleague是抽象同事类；ConcreteMediator是具体中介者对象，实现抽象类的方法，它需要知道所有具体同事类，并从具体同事接收消息，向具体同事对象发出命令；ConcreteColleague是具体同事类，每个具体同事只知道自己的行为，而不了解其它同事类的情况，但它们却都认识中介者对象。</p>
<p>代码实现：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//中介者抽象类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">Mediator</span> &#123;</span><br><span class="line">    <span class="comment">//注册同事</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">register</span><span class="params">(Colleague colleague)</span>;</span><br><span class="line">    <span class="comment">//通知中介者，发送消息</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">getAndSend</span><span class="params">(Colleague colleague)</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//同事抽象类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">Colleague</span> &#123;</span><br><span class="line">    <span class="comment">//中介者</span></span><br><span class="line">    <span class="keyword">protected</span> Mediator mediator;</span><br><span class="line">    <span class="comment">//接受消息</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">GetMessage</span><span class="params">()</span>;</span><br><span class="line">    <span class="comment">//发送消息</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">SendMessage</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setMediator</span><span class="params">(Mediator mediator)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.mediator = mediator;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//中介者实现类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ConcreteMediator</span> <span class="keyword">implements</span> <span class="title class_">Mediator</span> &#123;</span><br><span class="line">    <span class="comment">//被中介者代理的同事</span></span><br><span class="line">    <span class="keyword">private</span> List&lt;Colleague&gt; colleagues;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ConcreteMediator</span><span class="params">()</span> &#123;</span><br><span class="line">        colleagues = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">register</span><span class="params">(Colleague colleague)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (!colleagues.contains(colleague)) &#123;</span><br><span class="line">            <span class="comment">//同时给同事类确定其中介者</span></span><br><span class="line">            colleague.setMediator(<span class="built_in">this</span>);</span><br><span class="line">            <span class="built_in">this</span>.colleagues.add(colleague);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//接受消息并发送消息</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">getAndSend</span><span class="params">(Colleague colleague)</span> &#123;</span><br><span class="line">        colleagues.forEach(c -&gt; &#123;</span><br><span class="line">            <span class="keyword">if</span> (!c.equals(colleague)) &#123;</span><br><span class="line">                c.receive();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//具体的同事类1</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ConcreteColleague1</span> <span class="keyword">extends</span> <span class="title class_">Colleague</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">GetMessage</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;colleague1 receive message.&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">SendMessage</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;colleague1 send message.&quot;</span>);</span><br><span class="line">        <span class="comment">//请中介者转发</span></span><br><span class="line">        <span class="built_in">this</span>.mediator.getAndSend(<span class="built_in">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//具体的同事类2</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ConcreteColleague2</span> <span class="keyword">extends</span> <span class="title class_">Colleague</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">GetMessage</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;colleague2 receive message.&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">SendMessage</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;colleague2 send message.&quot;</span>);</span><br><span class="line">        <span class="comment">//请中介者转发</span></span><br><span class="line">        <span class="built_in">this</span>.mediator.getAndSend(<span class="built_in">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//调用</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//构建中介者</span></span><br><span class="line">        <span class="type">Mediator</span> <span class="variable">mediator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ConcreteMediator</span>();</span><br><span class="line">        <span class="comment">//构建具体的同事类</span></span><br><span class="line">        <span class="type">Colleague</span> <span class="variable">colleague1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ConcreteColleague1</span>();</span><br><span class="line">        <span class="type">Colleague</span> <span class="variable">colleague2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ConcreteColleague2</span>();</span><br><span class="line">        <span class="comment">//注册同事</span></span><br><span class="line">        mediator.register(colleague1);</span><br><span class="line">        mediator.register(colleague2);</span><br><span class="line">        <span class="comment">//发送消息</span></span><br><span class="line">        colleague1.send();</span><br><span class="line">        colleague2.send();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//上面的代码是简化了，可以用hashmap来存放同事对象，给不同的同事不同的key(名字)，这样可以实现对某一个对象的发送消息</span></span><br></pre></td></tr></table></figure>

<h3 id="备忘录模式"><a href="#备忘录模式" class="headerlink" title="备忘录模式"></a>备忘录模式</h3><p>游戏存档时，传统的方式，一个对象，就对应一个保存对象状态的对象，这样当游戏的对象很多时，不 利于管理，开销也很大。</p>
<p>传统的方式是简单地做备份，new出另外一个对象出来，再把需要备份的数据放到这个新对象，但这就暴露了对象内部的细节。</p>
<p>备忘录模式（Memento Pattern）：在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。</p>
<p>备忘录对象主要用来记录一个对象的某种状态，或者某些数据，当要做回退时，可以从备忘录对象里获取原来的数据进行恢复操作。</p>
<p>代码实现</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//需要记录的对象</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Originator</span> &#123;</span><br><span class="line">   <span class="keyword">private</span> String state;<span class="comment">//状态信息</span></span><br><span class="line">   <span class="keyword">public</span> String <span class="title function_">getState</span><span class="params">()</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> state;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setState</span><span class="params">(String state)</span> &#123;</span><br><span class="line">      <span class="built_in">this</span>.state = state;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">//编写一个方法，可以保存一个状态对象 Memento</span></span><br><span class="line">   <span class="keyword">public</span> Memento <span class="title function_">saveStateMemento</span><span class="params">()</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Memento</span>(state);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">//通过备忘录对象，恢复状态</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">getStateFromMemento</span><span class="params">(Memento memento)</span> &#123;</span><br><span class="line">      state = memento.getState();</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//备忘录对象</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Memento</span> &#123;</span><br><span class="line">	<span class="keyword">private</span> String state;</span><br><span class="line">	<span class="comment">//构造器</span></span><br><span class="line">	<span class="keyword">public</span> <span class="title function_">Memento</span><span class="params">(String state)</span> &#123;</span><br><span class="line">		<span class="built_in">super</span>();</span><br><span class="line">		<span class="built_in">this</span>.state = state;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">public</span> String <span class="title function_">getState</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="keyword">return</span> state;</span><br><span class="line">	&#125;	</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//存放备忘录对象</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Caretaker</span> &#123;</span><br><span class="line">	<span class="comment">//在List 集合中会有很多的备忘录对象</span></span><br><span class="line">	<span class="keyword">private</span> List&lt;Memento&gt; mementoList = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;Memento&gt;();</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">(Memento memento)</span> &#123;</span><br><span class="line">		mementoList.add(memento);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//获取到第index个Originator 的 备忘录对象(即保存状态)</span></span><br><span class="line">	<span class="keyword">public</span> Memento <span class="title function_">get</span><span class="params">(<span class="type">int</span> index)</span> &#123;</span><br><span class="line">		<span class="keyword">return</span> mementoList.get(index);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//客户端调用</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Client</span> &#123;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">		<span class="type">Originator</span> <span class="variable">originator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Originator</span>();</span><br><span class="line">		<span class="type">Caretaker</span> <span class="variable">caretaker</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Caretaker</span>();</span><br><span class="line">		originator.setState(<span class="string">&quot; 状态#1&quot;</span>);</span><br><span class="line">		<span class="comment">//保存了当前的状态</span></span><br><span class="line">		caretaker.add(originator.saveStateMemento());</span><br><span class="line">		originator.setState(<span class="string">&quot; 状态#2&quot;</span>);</span><br><span class="line">		caretaker.add(originator.saveStateMemento());	</span><br><span class="line">		<span class="comment">//将 originator 恢复到状态1</span></span><br><span class="line">		originator.getStateFromMemento(caretaker.get(<span class="number">0</span>));</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果希望保存多个originator对象的不同时间的状态，只需要HashMap &lt;string,集合&gt;。</p>
<p><strong>核心就是不暴露Originator类的内部结构，专门用个类来保存</strong>。如果类的成员变量过多，势必会占用比较大的资源，而且每一次保存都会消耗一定 的内存, 这个需要注意。</p>
<h3 id="解释器模式"><a href="#解释器模式" class="headerlink" title="解释器模式"></a>解释器模式</h3><p>编译原理中，一个算术表达式通过词法分析器形成词法单元，而后这些词法单元再通过语法分析器构建语法分析树，最终形成一颗抽象的语法分析树。诸如此类的例子也有很多，比如编译器、正则表达式等等。</p>
<p>如果一种特定类型的问题发生的频率足够高，那么可能就值得将该问题的各个实例表述为一个简单语言中的句子，这样就可以构建一个解释器，该解释器通过解释这些句子来解决该问题。</p>
<p><strong>解释器模式（Interpreter）</strong>，给定一个语言，定义它的文法的一种表示，并定义一个解释器，这个解释器使用该表示来解释语言中的句子。角色分为：</p>
<p>抽象解释器（AbstractExpression）：具体的解释任务由各个实现类完成。</p>
<p>终结符表达式（TerminalExpression）：实现与文法中的元素相关联的解释操作，<strong>通常一个解释器模式中只有一个终结表达式</strong>，但有多个实例，对应不同的终结符。</p>
<p>非终结符表达式（NonterminalExpression）：<strong>文法中的每条规则对应于一个非终结表达式</strong>，非终结符表达式根据逻辑的复杂程度而增加，原则上每个文法规则都对应一个非终结符表达式</p>
<p>上下文（Context）: 上下文环境类,包含解释器之外的全局信息。</p>
<p>解释器模式最好的例子还是计算器，用解释器模式来构建一个简单的计算器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//解释器接口</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Expression</span> &#123;</span><br><span class="line">    <span class="type">int</span> <span class="title function_">interpreter</span><span class="params">(Context context)</span>;<span class="comment">//一定会有解释方法</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//抽象非终结符表达式</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">NonTerminalExpression</span> <span class="keyword">implements</span> <span class="title class_">Expression</span>&#123;</span><br><span class="line">    Expression e1,e2;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">NonTerminalExpression</span><span class="params">(Expression e1, Expression e2)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.e1 = e1;</span><br><span class="line">        <span class="built_in">this</span>.e2 = e2;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//减法表达式实现类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MinusOperation</span> <span class="keyword">extends</span> <span class="title class_">NonTerminalExpression</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">MinusOperation</span><span class="params">(Expression e1, Expression e2)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(e1, e2);</span><br><span class="line">    &#125;</span><br><span class="line"> <span class="comment">//将两个表达式相减</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">interpreter</span><span class="params">(Context context)</span> &#123;</span><br><span class="line">        <span class="comment">//先调用e1,e2的interpreter()方法，有那么一点递归的意思</span></span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.e1.interpreter(context) - <span class="built_in">this</span>.e2.interpreter(context);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//加法表达式实现类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PlusOperation</span> <span class="keyword">extends</span> <span class="title class_">NonTerminalExpression</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">PlusOperation</span><span class="params">(Expression e1, Expression e2)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(e1, e2);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//将两个表达式相加</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">interpreter</span><span class="params">(Context context)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.e1.interpreter(context) + <span class="built_in">this</span>.e2.interpreter(context);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//终结符表达式，只有一个（在这个例子，用来存放数字，或者代表数字的字符）</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TerminalExpression</span> <span class="keyword">implements</span> <span class="title class_">Expression</span>&#123;</span><br><span class="line">    String variable;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">TerminalExpression</span><span class="params">(String variable)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.variable = variable;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">interpreter</span><span class="params">(Context context)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> context.lookup(<span class="built_in">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//上下文类（这里主要用来将变量解析成数字,当然一开始要先定义存到map）</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Context</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> Map&lt;Expression, Integer&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">    <span class="comment">//定义变量</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">add</span><span class="params">(Expression s, Integer value)</span>&#123;</span><br><span class="line">        map.put(s, value);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//将变量转换成数字</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">lookup</span><span class="params">(Expression s)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> map.get(s);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//调用</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Context</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Context</span>();</span><br><span class="line">        <span class="type">TerminalExpression</span> <span class="variable">a</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TerminalExpression</span>(<span class="string">&quot;a&quot;</span>);</span><br><span class="line">        <span class="type">TerminalExpression</span> <span class="variable">b</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TerminalExpression</span>(<span class="string">&quot;b&quot;</span>);</span><br><span class="line">        <span class="type">TerminalExpression</span> <span class="variable">c</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TerminalExpression</span>(<span class="string">&quot;c&quot;</span>);</span><br><span class="line">        context.add(a, <span class="number">4</span>);</span><br><span class="line">        context.add(b, <span class="number">8</span>);</span><br><span class="line">        context.add(c, <span class="number">2</span>);</span><br><span class="line">        System.out.println(<span class="keyword">new</span> <span class="title class_">MinusOperation</span>(<span class="keyword">new</span> <span class="title class_">PlusOperation</span>(a,b), c).interpreter(context));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>非终结符表达式（相当于树的树杈）</strong>：在这个例子中就是相加，相减的表达式，称为非终结符，当运算遇到这类的表达式的时候，必须先把非终结符的结果计算出来，犹如剥茧一般，一层一层的调用。</p>
<p><strong>终结符表达式（相当于树的叶子）</strong>：遇到这个表达式interpreter执行能直接返回结果，不会向下继续调用。</p>
<p><strong>源码</strong></p>
<p>Spring框架中 SpelExpressionParser就使用到解释器模式</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">SpelExpressionParser</span> <span class="variable">parser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SpelExpressionParser</span>();</span><br><span class="line"><span class="type">Expression</span> <span class="variable">expression</span> <span class="operator">=</span> parser.parseExpression(<span class="string">&quot;100 * (2 + 400) * 1 + 66&quot;</span>);</span><br><span class="line"><span class="type">int</span> <span class="variable">result</span> <span class="operator">=</span> (Integer) expression.getValue();</span><br><span class="line"></span><br><span class="line"><span class="comment">//Expression 接口,表达式接口</span></span><br><span class="line"><span class="comment">//下面有不同的实现类，比如SpelExpression, 或者CompositeStringExpression。</span></span><br><span class="line"><span class="comment">//使用时候，根据你创建的不同的Parser 对象，返回不同的 Expression 对象</span></span><br><span class="line"><span class="keyword">public</span> Expression <span class="title function_">parseExpression</span><span class="params">(String expressionString, ParserContext context)</span> <span class="keyword">throws</span> ParseException &#123;</span><br><span class="line">	<span class="keyword">if</span> (context == <span class="literal">null</span>) &#123;</span><br><span class="line">		context = NON_TEMPLATE_PARSER_CONTEXT;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">if</span> (context.isTemplate()) &#123;</span><br><span class="line">		<span class="keyword">return</span> parseTemplate(expressionString, context); <span class="comment">//返回的就是 CompositeStringExpression</span></span><br><span class="line">	&#125;<span class="keyword">else</span> &#123;</span><br><span class="line">		<span class="keyword">return</span> doParseExpression(expressionString, context); <span class="comment">//返回的就是 SpelExpression</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>小结</p>
<p>当有一个语言需要解释执行，可将该语言中的句子表示为一个抽象语法树，就可以 考虑使用解释器模式，让程序具有良好的扩展性；</p>
<p>应用场景：编译器、运算表达式计算、正则表达式等</p>
<p>使用解释器可能带来的问题：解释器模式会引起类膨胀、解释器模式采用递归调用方法，将会导致调试非常复杂、效率可能降低。</p>
<h3 id="状态模式"><a href="#状态模式" class="headerlink" title="状态模式"></a>状态模式</h3><p>状态模式（State Pattern）：它主要用来解决对象在多种状态转换时，需要对外输出不同的行为的问题。状态和行为是一一对应的，状态之间可以相互转换。当一个对象的内在状态改变时，允许改变其行为，这个对象看起来像是改变了其类。</p>
<p>代码实现</p>
<p><strong>Context类</strong>：环境角色具有两个职责，即处理本状态必须完成的任务，及决定是否可以过渡到其它状态。对于环境角色，有几个不成文的约束：</p>
<ul>
<li>即把状态对象声明为静态常量，有几个状态对象就声明几个状态常量</li>
<li>环境角色具有状态抽象角色定义的所有行为，具体执行使用委托方式</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Context</span> &#123;</span><br><span class="line">    <span class="comment">//定义状态</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="type">State</span> <span class="variable">STATE1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ConcreteState1</span>(<span class="built_in">this</span>);</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="type">State</span> <span class="variable">STATE2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ConcreteState2</span>(<span class="built_in">this</span>);</span><br><span class="line">    <span class="comment">//当前状态</span></span><br><span class="line">    <span class="keyword">private</span> State currentState;</span><br><span class="line">    <span class="comment">//获得当前状态</span></span><br><span class="line">    <span class="keyword">public</span> State <span class="title function_">getCurrentState</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> currentState;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//设置当前状态</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setCurrentState</span><span class="params">(State currentState)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.currentState = currentState;</span><br><span class="line">		<span class="comment">//System.out.println(&quot;当前状态：&quot; + currentState);</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">handle1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.currentState.handle1();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">handle2</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.currentState.handle2();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>State抽象状态类</strong>：抽象环境中声明一个环境角色，提供各个状态类自行访问，并且提供所有状态的抽象行为，由各个实现类实现。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">State</span> &#123;</span><br><span class="line">	<span class="comment">//环境角色</span></span><br><span class="line">    <span class="keyword">protected</span> Context context;</span><br><span class="line">    <span class="comment">//行为1</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">handle1</span><span class="params">()</span>;</span><br><span class="line">    <span class="comment">//行为2</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">handle2</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>具体状态</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ConcreteState1</span> <span class="keyword">extends</span> <span class="title class_">State</span> &#123;</span><br><span class="line">        </span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ConcreteState1</span><span class="params">(Context context)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>.context = context;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">handle1</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;ConcreteState1 的 handle1 方法&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">handle2</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">//可以假设执行方法2后会切换状态</span></span><br><span class="line">        <span class="built_in">super</span>.context.setCurrentState(Context.STATE2);</span><br><span class="line">        System.out.println(<span class="string">&quot;ConcreteState1 的 handle2 方法&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>调用</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Client</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//定义环境角色</span></span><br><span class="line">        <span class="type">Context</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Context</span>();</span><br><span class="line">        <span class="comment">//初始化状态</span></span><br><span class="line">        context.setCurrentState(Context.STATE1);</span><br><span class="line">        <span class="comment">//行为执行</span></span><br><span class="line">        context.handle1();</span><br><span class="line">        context.handle2();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>小结</p>
<p>状态模式将每个状态的行为封装到对应的一个类中，代码有很强的可读性，方便维护，将容易产生问题的if-else语句删除了。</p>
<p>符合“开闭原则”。容易增删状态。</p>
<p>会产生很多类。每个状态都要一个对应的类，当状态过多时会产生很多类，加大维护难度。</p>
<p>应用场景：当一个事件或者对象有很多种状态，状态之间会相互转换，对不同的状 态要求有不同的行为的时候，可以考虑使用状态模式，比如订单状态。</p>
<h3 id="策略模式"><a href="#策略模式" class="headerlink" title="策略模式"></a>策略模式</h3><p>有个鸭子项目：有各种鸭子(比如 野鸭、北京鸭、水鸭等， 鸭子有各种行为，比如 叫、飞行等)</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">Duck</span> &#123;</span><br><span class="line">   <span class="keyword">public</span> <span class="title function_">Duck</span><span class="params">()</span> &#123;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">display</span><span class="params">()</span>;<span class="comment">//显示鸭子信息</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">quack</span><span class="params">()</span> &#123;</span><br><span class="line">      System.out.println(<span class="string">&quot;鸭子嘎嘎叫~~&quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">swim</span><span class="params">()</span> &#123;</span><br><span class="line">      System.out.println(<span class="string">&quot;鸭子会游泳~~&quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">fly</span><span class="params">()</span> &#123;</span><br><span class="line">      System.out.println(<span class="string">&quot;鸭子会飞翔~~~&quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>其它鸭子，都继承了Duck类，所以fly让所有子类都会飞了，这是不正确的。</p>
<p><strong>继承带来的问题：对类的局部改动，尤其超类的局部改动，会影响其他部分。会有溢出效应。</strong></p>
<p>以通过覆盖fly方法来解决，如果有一个玩具鸭子ToyDuck, 这样就需要ToyDuck去覆盖Duck 的所有实现的方法。</p>
<p><strong>策略模式</strong>（Strategy Pattern）中，定义算法族，分别封装起来，让他们之间可以互相替换，此模式让算法的变化独立于使用算法的客户。</p>
<p>这算法体现了几个设计原则，第一、把变化的代码从不变的代码中分离出来； 第二、针对接口编程而不是具体类（定义了策略接口）；第三、多用组合/聚合，少用继承（客户通过组合方式使用策略）。</p>
<p>利用策略模式改进代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">FlyBehavior</span> &#123;</span><br><span class="line">   <span class="keyword">void</span> <span class="title function_">fly</span><span class="params">()</span>; <span class="comment">// 子类具体实现</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NoFlyBehavior</span> <span class="keyword">implements</span> <span class="title class_">FlyBehavior</span>&#123;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">fly</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="comment">// TODO Auto-generated method stub</span></span><br><span class="line">		System.out.println(<span class="string">&quot; 不会飞翔  &quot;</span>);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">GoodFlyBehavior</span> <span class="keyword">implements</span> <span class="title class_">FlyBehavior</span> &#123;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">fly</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="comment">// TODO Auto-generated method stub</span></span><br><span class="line">		System.out.println(<span class="string">&quot; 飞翔技术高超 ~~~&quot;</span>);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//让Duck聚合fly的接口</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">Duck</span> &#123;</span><br><span class="line">	<span class="comment">//属性, 策略接口</span></span><br><span class="line">	FlyBehavior flyBehavior;</span><br><span class="line">	<span class="keyword">public</span> <span class="title function_">Duck</span><span class="params">()</span> &#123;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">display</span><span class="params">()</span>;<span class="comment">//显示鸭子信息</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">quack</span><span class="params">()</span> &#123;</span><br><span class="line">		System.out.println(<span class="string">&quot;鸭子嘎嘎叫~~&quot;</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">swim</span><span class="params">()</span> &#123;</span><br><span class="line">		System.out.println(<span class="string">&quot;鸭子会游泳~~&quot;</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">fly</span><span class="params">()</span> &#123;	</span><br><span class="line">		<span class="keyword">if</span>(flyBehavior != <span class="literal">null</span>) &#123;</span><br><span class="line">			flyBehavior.fly();</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setFlyBehavior</span><span class="params">(FlyBehavior flyBehavior)</span> &#123;</span><br><span class="line">		<span class="built_in">this</span>.flyBehavior = flyBehavior;</span><br><span class="line">	&#125;	</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//Duck子类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WildDuck</span> <span class="keyword">extends</span> <span class="title class_">Duck</span> &#123;</span><br><span class="line">	<span class="comment">//构造器，传入FlyBehavor 的对象</span></span><br><span class="line">	<span class="keyword">public</span>  <span class="title function_">WildDuck</span><span class="params">()</span> &#123;</span><br><span class="line">		flyBehavior = <span class="keyword">new</span> <span class="title class_">GoodFlyBehavior</span>();</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">display</span><span class="params">()</span> &#123;</span><br><span class="line">		System.out.println(<span class="string">&quot; 这是野鸭 &quot;</span>);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>源码</strong></p>
<p>JDK的Comparator就使用了策略模式</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Comparator&lt;Integer&gt; comparator = <span class="keyword">new</span> <span class="title class_">Comparator</span>&lt;Integer&gt;() &#123;</span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compare</span><span class="params">(Integer o1, Integer o2)</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">   &#125;</span><br><span class="line">&#125;;</span><br><span class="line">Arrays.sort(data,comparator);</span><br></pre></td></tr></table></figure>

<p>new的一个匿名内部类，也就是实现Comparator接口（策略接口）的具体策略对象。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; <span class="keyword">void</span> <span class="title function_">sort</span><span class="params">(T[] a, Comparator&lt;? <span class="built_in">super</span> T&gt; c)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (c == <span class="literal">null</span>) &#123;</span><br><span class="line">        sort(a);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (LegacyMergeSort.userRequested)</span><br><span class="line">            legacyMergeSort(a, c);</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            TimSort.sort(a, <span class="number">0</span>, a.length, c, <span class="literal">null</span>, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Arrays.sort()中使用策略对象的排序方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//函数式接口(只有一个抽象方法)</span></span><br><span class="line"><span class="meta">@FunctionalInterface</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Comparator</span>&lt;T&gt; &#123;&#125;</span><br><span class="line"><span class="comment">//直接用lambda表达式做参数</span></span><br><span class="line">Arrays.sort(data,(var1,var2) -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span>(var1.compareTo(<span class="keyword">var</span>) &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>小结：</p>
<ul>
<li>策略模式的关键是：分析项目中变化部分与不变部分；</li>
<li>策略模式的核心思想是：多用组合/聚合 少用继承；用行为类组合，而不是行为的继承，更有弹性；</li>
<li>体现了“对修改关闭，对扩展开放”原则，客户端增加行为不用修改原有代码，只要添加一种策略（或者行为）即可。</li>
<li>提供了可以替换继承关系的办法： 策略模式将算法封装在独立的Strategy类中使得你可以独立于其Context改变它，使它易于切换、易于理解、易于扩展。</li>
<li>需要注意的是：每添加一个策略就要增加一个类，当策略过多是会导致类数目庞大。</li>
</ul>
<h3 id="职责链模式"><a href="#职责链模式" class="headerlink" title="职责链模式"></a>职责链模式</h3><p>假如有个项目：采购审批项目，根据金额的不同由不同的人审批。</p>
<p>传统方式是：接收到一个采购请求后，根据采购金额来调用对应的Approver (审批人)完成审批。</p>
<p>传统方式的问题 : 客户端这里会使用到分支判断(比如 switch) 来对不同的采购请求处理，这样如果各个级别的人员审批金额发生变化，在客户端的也需要变化；客户端必须明确的知道 有多少个审批级别和访问；这样对一个采购请求进行处理和Approver (审批人) 就存在强耦合关系，不利于代码的扩展和维护。</p>
<p><strong>职责链模式</strong>（Chain of Responsibility Pattern）,  又叫责任链模式，为请求创建了一个接收者对象的链。这种模式对请求的发送者和接收者进行解耦。 <strong>职责链模式通常每个接收者都包含对另一个接收者的引用</strong>。如果一个对象不能处理该请求， 那么它会把相同的请求传给下一个接收者，依此类推，形成一个链。</p>
<p>代码实现：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//抽象处理者</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">Approver</span> &#123;</span><br><span class="line">   Approver approver;  <span class="comment">//下一个处理者</span></span><br><span class="line">   String name; <span class="comment">// 名字</span></span><br><span class="line">   </span><br><span class="line">   <span class="keyword">public</span> <span class="title function_">Approver</span><span class="params">(String name)</span> &#123;</span><br><span class="line">      <span class="built_in">this</span>.name = name;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">//下一个处理者</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setApprover</span><span class="params">(Approver approver)</span> &#123;</span><br><span class="line">      <span class="built_in">this</span>.approver = approver;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">//处理审批请求的方法</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">processRequest</span><span class="params">(PurchaseRequest purchaseRequest)</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//具体处理者</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DepartmentApprover</span> <span class="keyword">extends</span> <span class="title class_">Approver</span> &#123;</span><br><span class="line">	<span class="keyword">public</span> <span class="title function_">DepartmentApprover</span><span class="params">(String name)</span> &#123;</span><br><span class="line">		<span class="built_in">super</span>(name);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">processRequest</span><span class="params">(PurchaseRequest purchaseRequest)</span> &#123;</span><br><span class="line">		<span class="keyword">if</span>(purchaseRequest.getPrice() &lt;= <span class="number">5000</span>) &#123;</span><br><span class="line">			System.out.println(<span class="string">&quot; 请求编号 id= &quot;</span> + purchaseRequest.getId() + <span class="string">&quot; 被 &quot;</span> + <span class="built_in">this</span>.name + <span class="string">&quot;处理&quot;</span>);</span><br><span class="line">		&#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">//将请求交给下一个处理者</span></span><br><span class="line">			approver.processRequest(purchaseRequest);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CollegeApprover</span> <span class="keyword">extends</span> <span class="title class_">Approver</span> &#123;</span><br><span class="line">	<span class="keyword">public</span> <span class="title function_">CollegeApprover</span><span class="params">(String name)</span> &#123;</span><br><span class="line">		<span class="built_in">super</span>(name);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">processRequest</span><span class="params">(PurchaseRequest purchaseRequest)</span> &#123;</span><br><span class="line">		<span class="keyword">if</span>(purchaseRequest.getPrice() &lt; <span class="number">5000</span> &amp;&amp; purchaseRequest.getPrice() &lt;= <span class="number">10000</span>) &#123;</span><br><span class="line">			System.out.println(<span class="string">&quot; 请求编号 id= &quot;</span> + purchaseRequest.getId() + <span class="string">&quot; 被 &quot;</span> + <span class="built_in">this</span>.name + <span class="string">&quot; 处理&quot;</span>);</span><br><span class="line">		&#125;<span class="keyword">else</span> &#123;</span><br><span class="line">			approver.processRequest(purchaseRequest);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SchoolMasterApprover</span> <span class="keyword">extends</span> <span class="title class_">Approver</span> &#123;</span><br><span class="line">	<span class="keyword">public</span> <span class="title function_">SchoolMasterApprover</span><span class="params">(String name)</span> &#123;</span><br><span class="line">		<span class="built_in">super</span>(name);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">processRequest</span><span class="params">(PurchaseRequest purchaseRequest)</span> &#123;</span><br><span class="line">		<span class="comment">// TODO Auto-generated method stub</span></span><br><span class="line">		<span class="keyword">if</span>(purchaseRequest.getPrice() &gt; <span class="number">10000</span>) &#123;</span><br><span class="line">			System.out.println(<span class="string">&quot; 请求编号 id= &quot;</span> + purchaseRequest.getId() + <span class="string">&quot; 被 &quot;</span> + <span class="built_in">this</span>.name + <span class="string">&quot; 处理&quot;</span>);</span><br><span class="line">		&#125;<span class="keyword">else</span> &#123;</span><br><span class="line">			approver.processRequest(purchaseRequest);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//请求类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PurchaseRequest</span> &#123;</span><br><span class="line">	<span class="keyword">private</span> <span class="type">int</span> <span class="variable">type</span> <span class="operator">=</span> <span class="number">0</span>; <span class="comment">//请求类型</span></span><br><span class="line">	<span class="keyword">private</span> <span class="type">float</span> <span class="variable">price</span> <span class="operator">=</span> <span class="number">0.0f</span>; <span class="comment">//请求金额</span></span><br><span class="line">	<span class="keyword">private</span> <span class="type">int</span> <span class="variable">id</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">	<span class="comment">//构造器</span></span><br><span class="line">	<span class="keyword">public</span> <span class="title function_">PurchaseRequest</span><span class="params">(<span class="type">int</span> type, <span class="type">float</span> price, <span class="type">int</span> id)</span> &#123;</span><br><span class="line">		<span class="built_in">this</span>.type = type;</span><br><span class="line">		<span class="built_in">this</span>.price = price;</span><br><span class="line">		<span class="built_in">this</span>.id = id;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getType</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="keyword">return</span> type;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">public</span> <span class="type">float</span> <span class="title function_">getPrice</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="keyword">return</span> price;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getId</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="keyword">return</span> id;</span><br><span class="line">	&#125;	</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//客户端调用</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Client</span> &#123;</span><br><span class="line">	<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">		<span class="comment">//创建一个请求</span></span><br><span class="line">		<span class="type">PurchaseRequest</span> <span class="variable">purchaseRequest</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PurchaseRequest</span>(<span class="number">1</span>, <span class="number">31000</span>, <span class="number">1</span>);</span><br><span class="line">		<span class="comment">//创建相关的审批人</span></span><br><span class="line">		<span class="type">DepartmentApprover</span> <span class="variable">departmentApprover</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DepartmentApprover</span>(<span class="string">&quot;张主任&quot;</span>);</span><br><span class="line">		<span class="type">CollegeApprover</span> <span class="variable">collegeApprover</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CollegeApprover</span>(<span class="string">&quot;李院长&quot;</span>);</span><br><span class="line">        <span class="type">SchoolMasterApprover</span> <span class="variable">schoolMasterApprover</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SchoolMasterApprover</span>(<span class="string">&quot;佟校长&quot;</span>);</span><br><span class="line">		<span class="comment">//需要将各个审批级别的下一个设置好 (处理人构成环形)</span></span><br><span class="line">		departmentApprover.setApprover(collegeApprover);</span><br><span class="line">		collegeApprover.setApprover(schoolMasterApprover);</span><br><span class="line">		schoolMasterApprover.setApprover(departmentApprover);</span><br><span class="line">		</span><br><span class="line">		departmentApprover.processRequest(purchaseRequest);</span><br><span class="line">        <span class="comment">//schoolMasterApprover.processRequest(purchaseRequest);</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>将处理者形成一个环形后，可以从任何一个处理者开始接受请求。如果是单向的责任链，那就只能从头让处理者接受请求（从张主任开始）。</p>
<p><strong>源码</strong></p>
<p>SpringMVC-HandlerExecutionChain 类就使用到职责链模式</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//DispatcherServlet类中的核心方法</span></span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doDispatch</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    <span class="type">HandlerExecutionChain</span> <span class="variable">mappedHandler</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    mappedHandler = <span class="built_in">this</span>.getHandler(processedRequest);<span class="comment">//获取到HandlerExecutionChain对象</span></span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    <span class="keyword">if</span> (!mappedHandler.applyPreHandle(processedRequest, response)) &#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">    mappedHandler.applyPostHandle(processedRequest, response, mv);</span><br><span class="line">&#125;</span><br><span class="line">  </span><br><span class="line"><span class="comment">//HandlerExecutionChain类的方法</span></span><br><span class="line"><span class="type">boolean</span> <span class="title function_">applyPreHandle</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    HandlerInterceptor[] interceptors = <span class="built_in">this</span>.getInterceptors();</span><br><span class="line">    <span class="keyword">if</span> (!ObjectUtils.isEmpty(interceptors)) &#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; interceptors.length; <span class="built_in">this</span>.interceptorIndex = i++) &#123;</span><br><span class="line">            <span class="comment">//拿到拦截器</span></span><br><span class="line">            <span class="type">HandlerInterceptor</span> <span class="variable">interceptor</span> <span class="operator">=</span> interceptors[i];</span><br><span class="line">            <span class="comment">//调用拦截器的方法</span></span><br><span class="line">            <span class="keyword">if</span> (!interceptor.preHandle(request, response, <span class="built_in">this</span>.handler)) &#123;</span><br><span class="line">                <span class="built_in">this</span>.triggerAfterCompletion(request, response, (Exception)<span class="literal">null</span>);</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> <span class="title function_">applyPostHandle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, <span class="meta">@Nullable</span> ModelAndView mv)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    HandlerInterceptor[] interceptors = <span class="built_in">this</span>.getInterceptors();</span><br><span class="line">    <span class="keyword">if</span> (!ObjectUtils.isEmpty(interceptors)) &#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> interceptors.length - <span class="number">1</span>; i &gt;= <span class="number">0</span>; --i) &#123;</span><br><span class="line">            <span class="comment">//拿到拦截器</span></span><br><span class="line">            <span class="type">HandlerInterceptor</span> <span class="variable">interceptor</span> <span class="operator">=</span> interceptors[i];</span><br><span class="line">            <span class="comment">//调用拦截器的方法</span></span><br><span class="line">            interceptor.postHandle(request, response, <span class="built_in">this</span>.handler, mv);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>也就是，mappedHandler先拿到一个拦截器，拦截器调用对应的方法，调用没成功，就再拿一个拦截器。</p>
<p>小结：</p>
<ul>
<li>将请求和处理分开，实现解耦，提高系统的灵活性；</li>
<li> 简化了对象，使对象不需要知道链的结构；</li>
<li>性能会受到影响，特别是在链比较长的时候，因此需控制链中最大节点数量，一般通过在Handler中设置一个最大节点数量，在setNext()方法中判断是否已经超过阀值，超过则不允许该链建立，避免出现超长链无意识地破坏系统性能；</li>
<li>调试不方便。采用了类似递归的方式，调试时逻辑可能比较复杂；</li>
<li> 最佳应用场景：有多个对象可以处理同一个请求时，比如：多级请求、请假/加薪 等审批流程、Java Web中Tomcat对Encoding的处理、拦截器；</li>
</ul>

      
    </div>
    <div class="article-footer">
      <blockquote class="mt-2x">
  <ul class="post-copyright list-unstyled">
    
    <li class="post-copyright-link hidden-xs">
      <strong>本文链接：</strong>
      <a href="https://skyung.gitee.io/Skyung/2022/03/01/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E2%80%94%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/" title="设计模式—行为型模式" target="_blank" rel="external">https://skyung.gitee.io/Skyung/2022/03/01/设计模式—行为型模式/</a>
    </li>
    
    <li class="post-copyright-license">
      <strong>版权声明： </strong> 本博客所有文章除特别声明外，均采用 <a href="http://creativecommons.org/licenses/by/4.0/deed.zh" target="_blank" rel="external">CC BY 4.0 CN协议</a> 许可协议。转载请注明出处！
    </li>
  </ul>
</blockquote>


<div class="panel panel-default panel-badger">
  <div class="panel-body">
    <figure class="media">
      <div class="media-left">
        <a href="https://github.com/cofess" target="_blank" class="img-burn thumb-sm visible-lg">
          <img src="/Skyung/images/avatar.jpg" class="img-rounded w-full" alt="">
        </a>
      </div>
      <div class="media-body">
        <h3 class="media-heading"><a href="https://github.com/cofess" target="_blank"><span class="text-dark">Skyung</span><small class="ml-1x">Web Developer</small></a></h3>
        <div>脚踏实地，仰望星空</div>
      </div>
    </figure>
  </div>
</div>


    </div>
  </article>
  
    
  <section id="comments">
  	
      <div id="uyan_frame"></div>
    
  </section>


  
</div>

  <nav class="bar bar-footer clearfix" data-stick-bottom>
  <div class="bar-inner">
  
  <ul class="pager pull-left">
    
    <li class="prev">
      <a href="/Skyung/2022/03/01/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E2%80%94%E7%BB%93%E6%9E%84%E5%9E%8B%E6%A8%A1%E5%BC%8F/" title="设计模式—结构型模式"><i class="icon icon-angle-left" aria-hidden="true"></i><span>&nbsp;&nbsp;上一篇</span></a>
    </li>
    
    
    <li class="next">
      <a href="/Skyung/2022/02/27/JVM/" title="JVM学习记录合集"><span>下一篇&nbsp;&nbsp;</span><i class="icon icon-angle-right" aria-hidden="true"></i></a>
    </li>
    
    
    <li class="toggle-toc">
      <a class="toggle-btn " data-toggle="collapse" href="#collapseToc" aria-expanded="false" title="文章目录" role="button">    <span>[&nbsp;</span><span>文章目录</span>
        <i class="text-collapsed icon icon-anchor"></i>
        <i class="text-in icon icon-close"></i>
        <span>]</span>
      </a>
    </li>
    
  </ul>
  
  
  <!-- Button trigger modal -->
  <button type="button" class="btn btn-fancy btn-donate pop-onhover bg-gradient-warning" data-toggle="modal" data-target="#donateModal"><span>赏</span></button>
  <!-- <div class="wave-icon wave-icon-danger btn-donate" data-toggle="modal" data-target="#donateModal">
    <div class="wave-circle"><span class="icon"><i class="icon icon-bill"></i></span></div>
  </div> -->
  
  
  <div class="bar-right">
    
    <div class="share-component" data-sites="weibo,qq,wechat,facebook,twitter" data-mobile-sites="weibo,qq,qzone"></div>
    
  </div>
  </div>
</nav>
  
<!-- Modal -->
<div class="modal modal-center modal-small modal-xs-full fade" id="donateModal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content donate">
      <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
      <div class="modal-body">
        <div class="donate-box">
          <div class="donate-head">
            <p>感谢您的支持，我会继续努力的!</p>
          </div>
          <div class="tab-content">
            <div role="tabpanel" class="tab-pane fade active in" id="alipay">
              <div class="donate-payimg">
                <img src="/Skyung/images/donate/alipay.jpg" alt="扫码支持" title="扫一扫" />
              </div>
              <p class="text-muted mv">扫码打赏，你说多少就多少</p>
              <p class="text-grey">打开支付宝扫一扫，即可进行扫码打赏哦</p>
            </div>
            <div role="tabpanel" class="tab-pane fade" id="wechatpay">
              <div class="donate-payimg">
                <img src="/Skyung/images/donate/wechat.jpg" alt="扫码支持" title="扫一扫" />
              </div>
              <p class="text-muted mv">扫码打赏，你说多少就多少</p>
              <p class="text-grey">打开微信扫一扫，即可进行扫码打赏哦</p>
            </div>
          </div>
          <div class="donate-footer">
            <ul class="nav nav-tabs nav-justified" role="tablist">
              <li role="presentation" class="active">
                <a href="#alipay" id="alipay-tab" role="tab" data-toggle="tab" aria-controls="alipay" aria-expanded="true"><i class="icon icon-alipay"></i> 支付宝</a>
              </li>
              <li role="presentation" class="">
                <a href="#wechatpay" role="tab" id="wechatpay-tab" data-toggle="tab" aria-controls="wechatpay" aria-expanded="false"><i class="icon icon-wepay"></i> 微信支付</a>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>



</main>

  <footer class="footer" itemscope itemtype="http://schema.org/WPFooter">
	
	
    <ul class="social-links">
    	
        <li><a href="/Skyung/null" target="_blank" title="Github" data-toggle=tooltip data-placement=top><i class="icon icon-github"></i></a></li>
        
        <li><a href="/Skyung/null" target="_blank" title="Weibo" data-toggle=tooltip data-placement=top><i class="icon icon-weibo"></i></a></li>
        
        <li><a href="/Skyung/null" target="_blank" title="Twitter" data-toggle=tooltip data-placement=top><i class="icon icon-twitter"></i></a></li>
        
        <li><a href="/Skyung/null" target="_blank" title="Behance" data-toggle=tooltip data-placement=top><i class="icon icon-behance"></i></a></li>
        
        <li><a href="/Skyung/atom.xml" target="_blank" title="Rss" data-toggle=tooltip data-placement=top><i class="icon icon-rss"></i></a></li>
        
    </ul>

    <div class="copyright">
    	
        <div class="publishby">
        	Theme by <a href="https://github.com/cofess" target="_blank"> cofess </a>base on <a href="https://github.com/cofess/hexo-theme-pure" target="_blank">pure</a>.
        </div>
    </div>
</footer>
  <script src="//cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script>
window.jQuery || document.write('<script src="js/jquery.min.js"><\/script>')
</script>

<script src="/Skyung/js/plugin.min.js"></script>


<script src="/Skyung/js/application.js"></script>


    <script>
(function (window) {
    var INSIGHT_CONFIG = {
        TRANSLATION: {
            POSTS: '文章',
            PAGES: '页面',
            CATEGORIES: '分类',
            TAGS: '标签',
            UNTITLED: '(未命名)',
        },
        ROOT_URL: '/Skyung/',
        CONTENT_URL: '/Skyung/content.json',
    };
    window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
</script>

<script src="/Skyung/js/insight.js"></script>






   




   
    
    <script defer type="text/javascript" src="http://v2.uyan.cc/code/uyan.js?uid=[object Object]"></script>








</body>
</html>